Русская справка по Delphi 5
Мастерская Delphi программирования.
Главная Мастерская Архив Отдых Для гостей  
Секреты VCL Секреты API Секреты AxtiveX        

Определение принтера по умолчанию.

Как выбрать принтер по умолчанию с помощью TPrinter вы конечно знаете. Если нет, открою Вам маленький секрет - надо присвоить свойству PrinterIndex значение -1. А вы не задумывались, что при этом происходит внутри класса Tprinter? Давайте вместе разберемся. Очевидно, что раз мы присваиваем значение свойству класса, необходимо рассмотреть метод, который отвечает за установку этого свойства. Ниже приведен код метода TPrinter.SetPrinterIndex.

procedure TPrinter.SetPrinterIndex(Value: Integer);
begin
  CheckPrinting(False);
  if (Value = -1) or (PrinterIndex = -1) then SetToDefaultPrinter
  else if (Value < 0) or (Value >= Printers.Count) then RaiseError(SPrinterIndexError);
  FPrinterIndex := Value;
  FreeFonts;
  SetState(psNoHandle);
end;

Что сразу бросается в глаза - это вызов приватного метода SetToDefaultPrinter когда вы устанавливаете свойство в -1. Очевидно, он и отвечает за выбор принтера, который используется системой по умолчанию. Рассмотрим, что этот метод делает.

procedure TPrinter.SetToDefaultPrinter;
var
  I: Integer;
  ByteCnt, StructCnt: DWORD;
  DefaultPrinter: array[0..79] of Char;
  Cur, Device: PChar;
  PrinterInfo: PPrinterInfo5;
begin
  ByteCnt := 0;
  StructCnt := 0;
  if not EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, nil, 0, ByteCnt,
    StructCnt) and (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
  begin
    // With no printers installed, Win95/98 fails above with "Invalid filename".
    // NT succeeds and returns a StructCnt of zero.
    if GetLastError = ERROR_INVALID_NAME then
      RaiseError(SNoDefaultPrinter)
    else
      RaiseLastWin32Error;
  end;
  PrinterInfo := AllocMem(ByteCnt);
  try
    EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, PrinterInfo, ByteCnt, ByteCnt,
      StructCnt);
    if StructCnt > 0 then
      Device := PrinterInfo.pPrinterName
    else begin
      GetProfileString('windows', 'device', '', DefaultPrinter,
        SizeOf(DefaultPrinter) - 1);
      Cur := DefaultPrinter;
      Device := FetchStr(Cur);
    end;
    with Printers do
      for I := 0 to Count-1 do
      begin
        if TPrinterDevice(Objects[I]).Device = Device then
        begin
          with TPrinterDevice(Objects[I]) do
            SetPrinter(PChar(Device), PChar(Driver), PChar(Port), 0);
          Exit;
        end;
      end;
  finally
    FreeMem(PrinterInfo);
  end;
  RaiseError(SNoDefaultPrinter);
end;

В первых строках своего кода метод определяет - "А стоит ли работать дальше? Может быть, в системе нет установленных принтеров".

if not EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, nil, 0, ByteCnt,
    StructCnt) and (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
  begin
    // With no printers installed, Win95/98 fails above with "Invalid filename".
    // NT succeeds and returns a StructCnt of zero.
    if GetLastError = ERROR_INVALID_NAME then
      RaiseError(SNoDefaultPrinter)
    else
      RaiseLastWin32Error;
  end;
Определяется это вызовом функции API EnumPrinters с параметром PRINTER_ENUM_DEFAULT. Одновременно определяется размер буфера, который будет содержать информацию о принтере. Размер буфера возвращается в переменной ByteCnt. Хочется отметить что, первый вызов EnumPrinters всегда заканчивается ошибкой. Вызывая GetLastError, определяем тип ошибки. В нашем случае это может быть ERROR_INSUFFICIENT_BUFFER - неверно задан размер буфера, или ERROR_INVALID_NAME - в Win98 не установлено ни одного принтера. В случае Win NT о наличии установленных принтеров сообщает переменная StructCnt. Если она равна 0, в Win NT не установлены принтеры.

После того как разобрались с наличием принтеров и размером буфера снова вызываем EnumPrinters, чтобы наконец-то узнать какой принтер система использует по умолчанию.

EnumPrinters(PRINTER_ENUM_DEFAULT, nil, 5, PrinterInfo, ByteCnt, ByteCnt,
      StructCnt);
О том, что такой принтер существует, сигнализирует переменная StructCnt. Если она не равна 0, значит, функция EnumPrinters вернула информацию о принтере. Сохраняем его имя в переменной Device. В противном случае пытаемся прочитать нужную информацию из файла Win.ini.
if StructCnt > 0 then
      Device := PrinterInfo.pPrinterName
    else begin
      GetProfileString('windows', 'device', '', DefaultPrinter,
        SizeOf(DefaultPrinter) - 1);
      Cur := DefaultPrinter;
      Device := FetchStr(Cur);
    end;

Остались сущие пустяки. Перебирая список принтеров, сравниваем их имена. При совпадении имен, делаем принтер текущем, вызвав метод SetPrinter.

with Printers do
      for I := 0 to Count-1 do
      begin
        if TPrinterDevice(Objects[I]).Device = Device then
        begin
          with TPrinterDevice(Objects[I]) do
            SetPrinter(PChar(Device), PChar(Driver), PChar(Port), 0);
          Exit;
        end;
      end;
Не будем подробно рассматривать работу метода. Единственное на что следует обратить внимание - это строка:
...
FPrinterIndex := J;
...

Из сказанного выше можно сделать вывод: Значение свойства PrinterIndex никогда не установится в -1. После завершения работы метода значение PrinterIndex будет содержать индекс принтера используемого системой по умолчанию не равного -1. Таким образом найти имя принтера по умолчанию из списка принтеров класса TPrinter не составляет больших усилий. Попробуйте определить принтер по умолчанию на своей машине, скомпилировав пример.


Главная Мастерская Архив Отдых Для гостей  
Секреты VCL Секреты API Секреты AxtiveX        
Дизайн и программирование - Valler© ,2000,2001.
http://www.valler.narod.ru


Используются технологии uCoz